﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WhutDoomCheck.Server.Configs;
using WhutDoomCheck.Server.Entities;
using WhutDoomCheck.Server.Extentions;
using WhutDoomCheck.Server.Services;
using WhutDoomCheck.Shared.HttpModels;

namespace WhutDoomCheck.Server.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StudentController : ControllerBase
    {
        public StudentController(ApplicationDbContext dbContext, RecordService recordService)
        {
            this.recordService = recordService;
            this.dbContext = dbContext;
        }

        private readonly ApplicationDbContext dbContext;
        private readonly RecordService recordService;

        /// <summary>
        /// 获取宿舍
        /// </summary>
        /// <returns></returns>
        [HttpGet("[Action]")]
        [Authorize(IdentityPolicyNames.Student)]
        public IActionResult GetDoom()
        {
            var sno = this.GetIdentifier();

            // 校外住宿，没有宿舍，走左边流程
            var student = dbContext.Students.Where(x => x.Sno == sno).Include(x => x.Doom).Single();
            if (!student.IsInSchool) return Ok(null);

            // 校内住宿或保留宿舍，就算查不出记录，也给一个错误的宿舍
            // 查不出记录的原因：数据表中学生原有宿舍信息无法匹配到任何一个合法的宿舍

            var doom = student.Doom ?? dbContext.Dooms.First();

            return Ok(new Bed(doom.Region, doom.Area, doom.Building, doom.Floor, doom.RoomNumber, student.BedNum ?? 0));
        }

        /// <summary>
        /// 获取学生信息
        /// </summary>
        /// <returns></returns>
        [HttpGet("[Action]")]
        [Authorize(IdentityPolicyNames.Student)]
        public IActionResult GetProfile()
        {
            var sno = this.GetIdentifier();

            var status = recordService.GetState(sno);

            var profile = dbContext.Students.AsNoTracking()
                                            .Where(x => x.Sno == sno)
                                            .Select(x => new Profile(x.Name, x.Grade, x.Ethnic, x.School,
                                                           x.Gender, x.CultureMethod, x.Major, x.Contact, status))
                                            .Single();
            return Ok(profile);
        }

        /// <summary>
        /// 无宿舍学生更新校外住宿信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("[Action]")]
        [Authorize(IdentityPolicyNames.Student)]
        public async Task<IActionResult> UpdateHotel([FromBody] UpdateHotelRequest request)
        {
            var sno = this.GetIdentifier();
            var student = dbContext.Students.Where(x => x.Sno == sno).Include(x => x.Doom).Single();

            var oldAddress  = student.Address;
            student.Address = request.Address;
            student.IsInSchool = false;
            student.DoomId = null;
            await dbContext.SaveChangesAsync();

            await recordService.AddAsync(sno, null, null, oldAddress, request.Address);

            return Ok();
        }

        /// <summary>
        /// 有宿舍学生更新宿舍信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("[Action]")]
        [Authorize(IdentityPolicyNames.Student)]
        public async Task<IActionResult> UpdateDoom([FromBody] UpdateDoomRequest request)
        {
            var newDoom = dbContext.Dooms.AsNoTracking()
                                         .Where(x => x.Area == request.Area)
                                         .Where(x => x.Building == request.Building)
                                         .Where(x => x.RoomNumber == request.Room)
                                         .SingleOrDefault();
            if (newDoom is null) return BadRequest();

            var sno = this.GetIdentifier();
            var student = dbContext.Students.Where(x => x.Sno == sno).Include(x => x.Doom).Single();

            var oldDoom = student.Doom;
            var oldAddress = student.Address ?? string.Empty;
            var newAddress = request.HotelAddress ?? string.Empty;

            // 床位号修改
            student.BedNum = request.BedNumber;

            // 更新信息
            student.DoomId = newDoom.Id;
            student.Address = newAddress;
            student.IsInSchool = true;
            await dbContext.SaveChangesAsync();

            await recordService.AddAsync(sno, oldDoom?.Id, newDoom.Id, oldAddress, newAddress);

            var modified = (oldAddress != newAddress) || (oldDoom?.Id != newDoom.Id);
            if (!modified && !request.ForceConfirm)
            {
                await recordService.SetStateAsync(sno, Status.Finished);
            }

            return Ok();
        }
    }
}
